<?php

namespace xssg\home\controller;

use Phalcon\Db\Column;

class Install extends \xssg\sys\Controller
{

    public function index()
    {
        $response = \Phalcon\Di::getDefault()->get("response");
        $url = \Phalcon\Di::getDefault()->get("url");
        $this->view->disable();
        return $response->redirect($url->get("install/index2", ["module" => 0]));
    }

    /**
     * 安装
     */
    public function index2()
    {
        $request = \Phalcon\Di::getDefault()->get("request");
        $response = \Phalcon\Di::getDefault()->get("response");
        $module = $request->getQuery("module", "int", 0);
        $table = $request->getQuery("table", "int", 0);
        if (!$module) {
            // 模块为0
            return $response->redirect($this->url->get("install/index2", ["module" => $module + 1]));
        }

        if (!$table) {
            // 表为0
            return $response->redirect($this->url->get("install/index2", [
                "module" => $module, "table" => $table + 1]));
        }
        $this->index_call($module, $table);


    }

    /**
     * 执行
     */
    private function index_call(int $module, int $table)
    {

        $modules = new \xssg\sys\Database();
        $moduledata = $modules->modules;
        if (isset($moduledata[$module - 1])) {
            $nowmodule = $moduledata[$module - 1];
            $nowmodulecalss = "\xssg\sys\database\\" . ucfirst($nowmodule);
            $tables = new $nowmodulecalss();
            $tablesdata = $tables->table;
            if (isset($tablesdata[$table - 1])) {
                $nowtable = $tablesdata[$table - 1];

                $nowmodulecalss = strtolower($nowmodulecalss) . "\\" . ucfirst($nowtable);
                $nowtable_obj = new $nowmodulecalss();
                return $this->table_call($tables->prefix . '_' . $nowtable, get_object_vars($nowtable_obj));
            }
            // 表不存在
            return -2;
        }
        // 模块不存在
        return -1;
    }

    /**
     * 表 处理
     */
    private function table_call(string $table_name, array $table_data)
    {


        $install = $this->db->tableExists($table_name);
        $this->view->setVar("install", $install);
        if ($install) {
            #
            return $this->table_update($table_name, $table_data);
        } else {
            //第一次创建,安装
            return $this->table_create($table_name, $table_data);

        }
    }

    /**
     * 表 创建
     */
    private function table_create(string $table_name, array $table_data)
    {
        return $this->db->createTable($table_name, null, $this->data_call($table_data));
    }

    /**
     * 处理表数据
     * @param $table_data
     */
    private function data_call($table_data)
    {
        $receives = [
            'columns' => [],
            'indexes' => [],
            'references' => [],
            'options' => []
        ];

        # 处理字段
        foreach ($table_data['columns'] as $k => $val) {
            $receives['columns'][] = new Column($k, $val);
        }
        # 处理索引
        foreach ($table_data['indexes'] as $name => $val) {
            $receives['indexes'][] = new \Phalcon\Db\Index($val['name'], $val['cloumns'], $val['type']);
        }
        # 处理约束
        foreach ($table_data['references'] as $k => $val) {
            $receives['references'][] = new \Phalcon\Db\Reference($val[0], $val[1]);
        }
        return $receives;
    }


    /**
     * 表 更新,升级
     */
    private function table_update(string $table_name, array $table_data)
    {
        $schemaName = null;
        # 处理 字段
        if (!$this->deal_update_columns($table_name, $schemaName, $table_data)) {
            return false;
        }

        // 处理 索引
        $this->deal_update_index($table_name, $schemaName, $table_data);


        //处理外键
        $referenceIndexList = $this->dealReferences($tableName, $schemaName, $table['field']['references']);

        $this->deletedTableFields($tableName, $schemaName, $dropFields);
        $dealPrimary = $this->editTableFields($tableName, $schemaName, $editFields);
        $this->addTableFields($tableName, $schemaName, $addFields);


    }

    /**
     * 处理索引
     *
     */
    private function deal_update_columns($table_name, $schemaName, $table_data)
    {

        #存在某个表 需要修改表信息
        $oldColumns = $this->db->describeColumns($table_name);
        list($dropFields, $addFields, $editFields, $oldFields) = [[], [], [], []];

        foreach ($oldColumns as $field) {
            $dropFields[$field->getName()] = $field;
            $oldFields[$field->getName()] = $field;
        }


        # 遍历修改字段
        foreach ($table_data['columns'] as $name => $column) {
            $columnob = new Column($name, $column);
            unset($dropFields[$name]);# 无需删除
            if (isset($oldFields[$name])) {
                # 修改
                if ($this->compareFiled($columnob, $oldFields[$name])) {
                    # 相同
                } else {
                    # 不同
                    $editFields[$name] = $columnob;
                }
            } else {
                # 增加
                $addFields[$name] = $columnob;
            }
        }
        # 删除字段
        if (!$this->deletedTableFields($table_name, $schemaName, $dropFields)) {
            return false;
        }
        # 添加字段
        if (!$this->addTableFields($table_name, $schemaName, $addFields)) {
            return false;
        }

        /**
         * 修改字段
         */
        if (!$this->editTableFields($table_name, $schemaName, $editFields)) {
            return false;
        }

        return true;
    }


    /**
     * 处理索引
     *
     */
    private function deal_update_index(string $tableName, $schemaName, array $table_data)
    {
        list($dropIndex, $addIndex) = array([], []);

        // 获取表的所有索引
        $indexesOld = $this->db->describeIndexes($tableName);

        foreach ($indexesOld as $oindex) {
            if ($oindex instanceof \Phalcon\Db\Index) {
                pr($oindex->getName(), $oindex->getType(), $oindex->getColumns());
                if (strtoupper($oindex->getType()) == 'PRIMARY') {
                    # 主键声明 跳过!
                    continue;
                }
                $indexName = $oindex->getName();

                pr($indexName);
            }

        }
        dd($indexesOld, $tableName);
        foreach ($fieldIndex as $index) {
            $indexName = $index->getName();
            if (strtoupper($index->getType()) == 'PRIMARY' || empty($index->getType())) {
                if ($dealPrimary) {
                    continue;
                }

                $columnsArr = empty($primaryKey) ? $index->getColumns() : array_keys($primaryKey);
                if ($columnsArr == $dropIndex['__PRIMARY__']->getColumns()) {
                    unset($dropIndex['__PRIMARY__']);
                    continue;
                }
            }

            if (array_key_exists($indexName, $dropIndex)) {
                //不一样就删掉 且新增
                if ($index->getType() == $dropIndex[$indexName]->getType()
                    && $index->getColumns() == $dropIndex[$indexName]->getColumns()) {
                    unset($dropIndex[$indexName]);
                    continue;
                }
            }

            $addIndex[] = $index;
        }

        var_dump($dropIndex);
        # 删除索引
        foreach ($dropIndex as $key => $value) {
            $this->connection->dropIndex($tableName, $schemaName, $key);
        }
        # 增加索引
        foreach ($addIndex as $index) {
            $this->connection->addIndex($tableName, $schemaName, $index);
        }
    }

    /**
     * 比较字段
     * @param \Phalcon\Db\Column $new
     * @param \Phalcon\Db\Column $old
     * @return bool
     */
    private function compareFiled(\Phalcon\Db\Column $new, \Phalcon\Db\Column $old): bool
    {
        return ($new->getType() == $old->getType()
            && $new->getSchemaName() == $old->getSchemaName()
            && $new->isPrimary() == $old->isPrimary()
            && $new->getSize() == $old->getSize()
            && $new->isUnsigned() == $old->isUnsigned()
            && $new->isAutoIncrement() == $old->isAutoIncrement()
            && $new->hasDefault() == $old->hasDefault()
            && $new->getSchemaName() == $old->getSchemaName()
            && $new->getDefault() == $old->getDefault()
            && $new->isNotNull() == $old->isNotNull());
    }


    /**
     * 删除字段
     * @param $tableName
     * @param $schemaName
     * @param $fieldArray
     * @return bool
     */
    private function deletedTableFields($tableName, $schemaName, $fieldArray)
    {
        if (empty($fieldArray)) {
            return true;
        }

        foreach ($fieldArray as $name => $value) {
            $re = $this->connection->dropColumn(
                $tableName,
                $schemaName,
                $name
            );
            if (!$re) {
                return $re;
            }
        }
        return true;
    }

    /**
     * 添加字段
     * @param $tableName
     * @param $schemaName
     * @param $columnArray
     * @return bool
     */
    private function addTableFields($tableName, $schemaName, $columnArray)
    {
        if (empty($columnArray)) {
            return true;
        }

        foreach ($columnArray as $column) {
            $re = $this->db->addColumn($tableName, $schemaName, $column);
            if (!$re) {
                return true;
            }
        }
        return true;
    }


    //修改字段
    private function editTableFields($tableName, $schemaName, $columnArray)
    {
        if (empty($columnArray)) {
            return true;
        }

        foreach ($columnArray as $column) {
            /**
             * @var $column \Phalcon\Db\Column
             */
            #设置自增时,主键必须搞定
            if ($column->isAutoIncrement() || $column->isPrimary()) {
                if (!$column->isPrimary()) {
                    dd($tableName . '修改自增字段失败, 因为他不是主键');
                }

                //修改主键为当前键 判断主键是否一致
                $indexes = $this->db->describeIndexes($tableName, $schemaName);
                $savePrimary = false;
                foreach ($indexes as $index) {
                    if (strtoupper($index->getType()) == 'PRIMARY') {
                        $savePrimary = true;
                        if ($index->getColumns() != [$column->getName()]) {
                            $this->connection->dropPrimaryKey($tableName, $schemaName);
                            $index = new Index($column->getName(), [$column->getName(), 'PRIMARY']);
                            $this->connection->addPrimaryKey($tableName, $schemaName, $index);
                        }
                        break;
                    }
                }
                if (!$savePrimary) {
                    $this->db->addPrimaryKey($tableName, $schemaName,
                        new Index($column->getName(), [$column->getName()])
                    );
                }
                $dealPrimary = true;
            }

            $re = $this->db->modifyColumn($tableName, $schemaName, $column);
            if (!$re) {
                return $re;
            }
        }

        return true;
    }


}